package com.example.maze;

import com.example.maze.generator.DivisionGenerator;
import com.example.maze.generator.KruskalGenerator;
import com.example.maze.generator.MazeGenerator;
import com.example.maze.model.Maze;
import com.example.maze.model.Cell;
import com.example.maze.model.Coordinate;
import com.example.maze.solver.*;
import com.example.maze.util.MazeVisualizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

/**
 * 迷宫生成和寻路算法演示程序
 * 
 * 使用方法：
 * java -jar maze.jar [width] [height] [algorithm]
 * 
 * 参数说明：
 * - width: 迷宫宽度（默认20）
 * - height: 迷宫高度（默认20）
 * - algorithm: 寻路算法 dfs|bfs|a-star|all（默认all）
 * 
 * @author maze-demo
 */
public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    
    private static final int DEFAULT_WIDTH = 20;
    private static final int DEFAULT_HEIGHT = 20;
    private static final String DEFAULT_ALGORITHM = "all";

    public static void main(String[] args) {
        try {
            // 解析命令行参数
            CommandLineArgs parsedArgs = parseArguments(args);
            
            System.out.println("=== 迷宫生成和寻路算法演示 ===");
            System.out.printf("迷宫尺寸: %d x %d%n", parsedArgs.width, parsedArgs.height);
            System.out.printf("寻路算法: %s%n", parsedArgs.algorithm);
            System.out.println();
            
            // 创建迷宫
            Maze maze = new Maze(parsedArgs.height, parsedArgs.width);
            
            // 选择生成器并生成迷宫
            MazeGenerator generator = selectGenerator();
            long genStartTime = System.currentTimeMillis();
            generator.generate(maze);
            long genTime = System.currentTimeMillis() - genStartTime;
            
            // 显示迷宫信息和原始迷宫
            MazeVisualizer.printMazeHeader(maze, generator.getName());
            MazeVisualizer.printMazeWithTitle(maze, "原始迷宫");
            System.out.printf("生成耗时: %d ms%n", genTime);
            
            // 根据指定算法进行寻路
            if (parsedArgs.algorithm.equals("all")) {
                List<SolverResult> results = solveAllAlgorithms(maze);
                // 显示结果对比
                MazeVisualizer.printSolverComparison(results);
                // 分别显示每种算法的路径
                displayAllAlgorithmPaths(maze, results);
            } else {
                List<SolverResult> results = solveMaze(maze, parsedArgs.algorithm);
                // 显示结果
                if (!results.isEmpty() && results.get(0).isFound()) {
                    displayDetailedResult(maze, results.get(0));
                }
            }
            
            // 显示图例
            MazeVisualizer.printLegend();
            
            // 交互模式
            if (parsedArgs.interactive) {
                runInteractiveMode(maze);
            }
            
        } catch (Exception e) {
            logger.error("程序执行错误", e);
            System.err.println("错误: " + e.getMessage());
            printUsage();
            System.exit(1);
        }
    }

    /**
     * 解析命令行参数
     */
    private static CommandLineArgs parseArguments(String[] args) {
        CommandLineArgs result = new CommandLineArgs();
        
        if (args.length >= 1) {
            try {
                result.width = Integer.parseInt(args[0]);
                if (result.width < 5 || result.width > 100) {
                    throw new IllegalArgumentException("宽度必须在5-100之间");
                }
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("无效的宽度参数: " + args[0]);
            }
        }
        
        if (args.length >= 2) {
            try {
                result.height = Integer.parseInt(args[1]);
                if (result.height < 5 || result.height > 100) {
                    throw new IllegalArgumentException("高度必须在5-100之间");
                }
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("无效的高度参数: " + args[1]);
            }
        }
        
        if (args.length >= 3) {
            String algo = args[2].toLowerCase();
            if (!Arrays.asList("dfs", "bfs", "a-star", "all").contains(algo)) {
                throw new IllegalArgumentException("无效的算法参数: " + args[2] + 
                    "，支持的算法: dfs, bfs, a-star, all");
            }
            result.algorithm = algo;
        }
        
        // 检查是否启用交互模式
        result.interactive = args.length >= 4 && args[3].equals("-i");
        
        return result;
    }

    /**
     * 运行所有算法并返回结果
     */
    private static List<SolverResult> solveAllAlgorithms(Maze maze) {
        List<SolverResult> results = new ArrayList<>();
        
        // 依次运行所有算法，但不清除访问痕迹
        maze.reset();
        results.add(new DFSSolver().solve(maze));
        
        maze.reset();
        results.add(new BFSSolver().solve(maze));
        
        maze.reset();
        results.add(new AStarSolver().solve(maze));
        
        return results;
    }

    /**
     * 显示所有算法的路径
     */
    private static void displayAllAlgorithmPaths(Maze originalMaze, List<SolverResult> results) {
        System.out.println("\n=== 各算法路径对比 ===");
        
        // 为每个算法创建独立的迷宫副本来显示路径
        for (SolverResult result : results) {
            if (result.isFound()) {
                // 创建迷宫副本
                Maze mazeCopy = copyMaze(originalMaze);
                
                // 标记路径
                MazeVisualizer.markAlgorithmPath(mazeCopy, result.getPath(), result.getAlgorithmName());
                
                // 显示迷宫
                String title = result.getAlgorithmName() + "算法路径 (长度: " + result.getPathLength() + ")";
                MazeVisualizer.printMazeWithTitle(mazeCopy, title);
            } else {
                System.out.println("\n" + result.getAlgorithmName() + "算法未找到路径");
            }
        }
        
        // 显示所有路径在同一个迷宫中的对比
        displayCombinedPaths(originalMaze, results);
    }

    /**
     * 在同一个迷宫中显示所有路径
     */
    private static void displayCombinedPaths(Maze originalMaze, List<SolverResult> results) {
        System.out.println("\n=== 所有路径合并显示 ===");
        
        Maze combinedMaze = copyMaze(originalMaze);
        
        // 按顺序标记所有路径
        for (SolverResult result : results) {
            if (result.isFound()) {
                markPathWithPriority(combinedMaze, result.getPath(), result.getAlgorithmName());
            }
        }
        
        MazeVisualizer.printMazeWithTitle(combinedMaze, "所有算法路径对比");
        
        // 显示路径统计
        System.out.println("\n路径统计:");
        for (SolverResult result : results) {
            if (result.isFound()) {
                System.out.printf("%s: %c 标记, 长度 %d%n", 
                    result.getAlgorithmName(), 
                    getAlgorithmChar(result.getAlgorithmName()),
                    result.getPathLength());
            }
        }
    }

    /**
     * 复制迷宫
     */
    private static Maze copyMaze(Maze original) {
        Maze copy = new Maze(original.getRows(), original.getCols());
        
        // 复制所有单元格的类型
        for (int row = 0; row < original.getRows(); row++) {
            for (int col = 0; col < original.getCols(); col++) {
                Cell originalCell = original.getCell(row, col);
                Cell.Type type = originalCell.getType();
                
                // 重置寻路相关的类型
                if (type == Cell.Type.VISITED || type == Cell.Type.SOLUTION ||
                    type == Cell.Type.DFS_PATH || type == Cell.Type.BFS_PATH || type == Cell.Type.ASTAR_PATH) {
                    type = Cell.Type.PATH;
                }
                
                copy.setCell(row, col, type);
            }
        }
        
        // 复制起点和终点
        if (original.getStart() != null) {
            copy.setStart(original.getStart());
        }
        if (original.getEnd() != null) {
            copy.setEnd(original.getEnd());
        }
        
        return copy;
    }

    /**
     * 按优先级标记路径（在同一个迷宫中显示多条路径时）
     */
    private static void markPathWithPriority(Maze maze, List<Coordinate> path, String algorithmName) {
        if (path == null || path.isEmpty()) {
            return;
        }
        
        for (Coordinate coord : path) {
            Cell cell = maze.getCell(coord);
            if (cell.getType() != Cell.Type.START && cell.getType() != Cell.Type.END) {
                // 只有在单元格是通路时才标记，避免覆盖其他算法的路径
                if (cell.getType() == Cell.Type.PATH) {
                    switch (algorithmName.toUpperCase()) {
                        case "DFS":
                            cell.setType(Cell.Type.DFS_PATH);
                            break;
                        case "BFS":
                            cell.setType(Cell.Type.BFS_PATH);
                            break;
                        case "A*":
                            cell.setType(Cell.Type.ASTAR_PATH);
                            break;
                    }
                }
            }
        }
    }

    /**
     * 获取算法对应的字符
     */
    private static char getAlgorithmChar(String algorithmName) {
        switch (algorithmName.toUpperCase()) {
            case "DFS": return 'D';
            case "BFS": return 'B';
            case "A*": return 'A';
            default: return '*';
        }
    }

    /**
     * 选择迷宫生成器
     */
    private static MazeGenerator selectGenerator() {
        // 可以随机选择生成器，或者根据需要选择
        return Math.random() < 0.5 ? new KruskalGenerator() : new DivisionGenerator();
    }

    /**
     * 根据指定算法进行寻路
     */
    private static List<SolverResult> solveMaze(Maze maze, String algorithm) {
        List<SolverResult> results = new ArrayList<>();
        
        switch (algorithm.toLowerCase()) {
            case "dfs":
                results.add(new DFSSolver().solve(maze));
                break;
            case "bfs":
                results.add(new BFSSolver().solve(maze));
                break;
            case "a-star":
                results.add(new AStarSolver().solve(maze));
                break;
            case "all":
            default:
                // 依次运行所有算法
                maze.reset();
                results.add(new DFSSolver().solve(maze));
                
                maze.reset();
                results.add(new BFSSolver().solve(maze));
                
                maze.reset();
                results.add(new AStarSolver().solve(maze));
                break;
        }
        
        return results;
    }

    /**
     * 显示详细的寻路结果
     */
    private static void displayDetailedResult(Maze maze, SolverResult result) {
        System.out.println("\n=== 详细寻路结果 ===");
        System.out.println(result);
        
        if (result.isFound()) {
            MazeVisualizer.printMazeWithTitle(maze, 
                result.getAlgorithmName() + "算法寻路结果");
        }
    }

    /**
     * 交互模式
     */
    private static void runInteractiveMode(Maze maze) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("\n=== 交互模式 ===");
        System.out.println("输入命令: dfs|bfs|a-star|all|reset|quit");
        
        while (true) {
            System.out.print("> ");
            String command = scanner.nextLine().trim().toLowerCase();
            
            switch (command) {
                case "quit":
                case "exit":
                    System.out.println("再见！");
                    return;
                case "reset":
                    maze.reset();
                    MazeVisualizer.printMazeWithTitle(maze, "重置后的迷宫");
                    break;
                case "dfs":
                case "bfs":
                case "a-star":
                case "all":
                    maze.reset();
                    List<SolverResult> results = solveMaze(maze, command);
                    if (results.size() > 1) {
                        MazeVisualizer.printSolverComparison(results);
                    } else if (!results.isEmpty()) {
                        displayDetailedResult(maze, results.get(0));
                    }
                    break;
                default:
                    System.out.println("未知命令: " + command);
                    System.out.println("可用命令: dfs, bfs, a-star, all, reset, quit");
                    break;
            }
        }
    }

    /**
     * 打印使用说明
     */
    private static void printUsage() {
        System.out.println("\n使用方法:");
        System.out.println("java -jar maze.jar [width] [height] [algorithm] [-i]");
        System.out.println();
        System.out.println("参数说明:");
        System.out.println("  width     - 迷宫宽度 (5-100, 默认20)");
        System.out.println("  height    - 迷宫高度 (5-100, 默认20)");
        System.out.println("  algorithm - 寻路算法: dfs|bfs|a-star|all (默认all)");
        System.out.println("  -i        - 启用交互模式");
        System.out.println();
        System.out.println("示例:");
        System.out.println("  java -jar maze.jar 30 20 a-star");
        System.out.println("  java -jar maze.jar 40 40 all -i");
    }

    /**
     * 命令行参数类
     */
    private static class CommandLineArgs {
        int width = DEFAULT_WIDTH;
        int height = DEFAULT_HEIGHT;
        String algorithm = DEFAULT_ALGORITHM;
        boolean interactive = false;
    }
}